/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.mindorks.placeholderview;

import com.mindorks.placeholderview.impl.ICardState;
import com.mindorks.placeholderview.impl.ItemRemovedListener;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.StackLayout;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;

import java.util.ArrayList;
import java.util.List;

/**
 * SwipeDirectionalView
 *
 * @since 2021-05-27
 */
public class SwipeDirectionalView extends StackLayout implements ICardState {
    /**
     * 左上
     */
    public static final int TOP_LEFT = 1;

    /**
     * 右上
     */
    public static final int TOP_RIGHT = 2;
    /**
     * 左下
     */
    public static final int BOTTOM_LEFT = 3;
    /**
     * 右下
     */
    public static final int BOTTOM_RIGHT = 4;

    /**
     * 默认滑动类型
     */
    public static final int SWIPE_TYPE_DEFAULT = 1;

    /**
     * 横向滑动
     */
    public static final int SWIPE_TYPE_HORIZONTAL = 2;

    private SwipeDecor mSwipeDecor = new SwipeDecor();
    private List<Component> componentList = new ArrayList<>();
    private ItemRemovedListener mItemRemovedListener;
    private int mDisplayViewCount = 3;
    private CardTouchEventListener cardTouchEventListener;
    private Component mTouchComponent;
    private Display displayMetrics;
    private Component cacheComponent;
    private int mSwipeType = SWIPE_TYPE_DEFAULT;
    private boolean isTouchAble = true;

    private int halfWidth;
    private int halfHeight;

    /**
     * 构造函数
     *
     * @param context 上下文
     */
    public SwipeDirectionalView(Context context) {
        this(context, null);
    }

    /**
     * 构造函数
     *
     * @param context 上下文
     * @param attrSet 属性
     */
    public SwipeDirectionalView(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    /**
     * 构造函数
     *
     * @param context   上下文
     * @param attrSet   属性
     * @param styleName 样式名
     */
    public SwipeDirectionalView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        this.mContext = context;
        cardTouchEventListener = new CardTouchEventListener(context, this);

        displayMetrics = DisplayManager.getInstance().getDefaultDisplay(getContext()).get();
        halfWidth = (int) (displayMetrics.getAttributes().width * 0.8);
        halfHeight = (int) (displayMetrics.getAttributes().height * 0.8);
    }

    public void setItemRemovedListener(ItemRemovedListener mItemRemovedListener) {
        this.mItemRemovedListener = mItemRemovedListener;
    }

    /**
     * 添加卡片
     *
     * @param component 卡片内容
     * @return SwipeDirectionalView
     */
    public SwipeDirectionalView addView(Component component) {
        LayoutConfig layoutConfig = new LayoutConfig();
        layoutConfig.alignment = LayoutAlignment.CENTER;
        component.setLayoutConfig(layoutConfig);
        componentList.add(component);
        if (componentList.size() <= mDisplayViewCount) {
            component.setScale(1 - mSwipeDecor.getRelativeScale() * componentList.indexOf(component), 1 - mSwipeDecor.getRelativeScale() * componentList.indexOf(component));
            layoutConfig = (LayoutConfig) component.getLayoutConfig();
            layoutConfig.setMarginTop(mSwipeDecor.getPaddingTop() * componentList.indexOf(component) - 1);
            component.setLayoutConfig(layoutConfig);
            addComponent(component, 0);

            if (componentList.indexOf(component) == 0) {
                setTouchComponent(component);
            }
        }
        return this;
    }

    @Override
    public void removeCardView(Component component, int removeType) {
        new EventHandler(EventRunner.getMainEventRunner()).postTask(() -> {
            cacheComponent = component;

            componentList.remove(component);
            removeComponent(component);

            if (componentList.size() >= mDisplayViewCount) {
                addComponent(componentList.get(mDisplayViewCount - 1), 0);
            }

            setViewScale();

            if (getChildCount() > 0) {
                setTouchComponent(getComponentAt(getChildCount() - 1));
            }

            if (mItemRemovedListener != null) {
                mItemRemovedListener.onItemRemoved(componentList.size());
            }
        });
    }

    @Override
    public void acceptCard(Component component) {
        if (component instanceof BaseSwipeCard) {
            ((BaseSwipeCard) component).showAccept();
        }
    }

    @Override
    public void rejectCard(Component component) {
        if (component instanceof BaseSwipeCard) {
            ((BaseSwipeCard) component).showReject();
        }
    }

    @Override
    public void resetCard(Component component) {
        if (component instanceof BaseSwipeCard) {
            ((BaseSwipeCard) component).hideAllTips();
        }
    }

    private void setViewScale() {
        int viewCount = getChildCount();
        for (int i = 0; i < viewCount; i++) {
            getComponentAt(i).setScale(1 - mSwipeDecor.getRelativeScale() * (viewCount - i - 1), 1 - mSwipeDecor.getRelativeScale() * (viewCount - i - 1));
            LayoutConfig layoutConfig = (LayoutConfig) getComponentAt(i).getLayoutConfig();
            layoutConfig.setMarginTop(mSwipeDecor.getPaddingTop() * (viewCount - i - 1));
            getComponentAt(i).setLayoutConfig(layoutConfig);
        }
    }

    private void setTouchComponent(Component component) {
        mTouchComponent = component;
        if (isTouchAble) {
            mTouchComponent.setTouchEventListener(cardTouchEventListener);
        }
    }

    /**
     * 选择
     *
     * @param swipe 是否接受
     */
    public void doSwipe(boolean swipe) {
        if (mTouchComponent == null) {
            return;
        }

        float rotate;
        int moveX;
        int moveY;
        if (swipe) {
            moveX = halfWidth;
            rotate = -cardTouchEventListener.cardRotation;
        } else {
            moveX = -halfWidth;
            rotate = cardTouchEventListener.cardRotation;
        }

        if (mSwipeType == SWIPE_TYPE_DEFAULT) {
            moveY = halfHeight;
        } else {
            moveY = (int) mTouchComponent.getContentPositionY();
            rotate = 0;
        }

        AnimatorProperty animatorProperty = mTouchComponent.createAnimatorProperty();
        animatorProperty
                .moveFromX(mTouchComponent.getContentPositionX())
                .moveToX(moveX)
                .moveFromY(mTouchComponent.getContentPositionY())
                .moveToY(moveY)
                .rotate(rotate)
                .setCurveType(Animator.CurveType.DECELERATE)
                .setDuration(300)
                .setStateChangedListener(new Animator.StateChangedListener() {
                    @Override
                    public void onStart(Animator animator) {
                        if (swipe) {
                            acceptCard(mTouchComponent);
                        } else {
                            rejectCard(mTouchComponent);
                        }
                    }

                    @Override
                    public void onStop(Animator animator) {
                    }

                    @Override
                    public void onCancel(Animator animator) {
                    }

                    @Override
                    public void onEnd(Animator animator) {
                        removeCardView(mTouchComponent, TOP_LEFT);
                    }

                    @Override
                    public void onPause(Animator animator) {
                    }

                    @Override
                    public void onResume(Animator animator) {
                    }
                }).start();
    }

    /**
     * 还原
     */
    public void undoLastSwipe() {
        if (cacheComponent != null) {
            if (cacheComponent instanceof BaseSwipeCard) {
                ((BaseSwipeCard) cacheComponent).hideAllTips();
            }
            undoLastSwipeAnima();
        }
    }

    private void undoLastSwipeAnima() {
        addComponent(cacheComponent);
        AnimatorProperty animatorProperty = cacheComponent.createAnimatorProperty();
        animatorProperty
                .moveFromX(cacheComponent.getContentPositionX())
                .moveToX(mTouchComponent.getContentPositionX())
                .moveFromY(cacheComponent.getContentPositionY())
                .moveToY(mTouchComponent.getContentPositionY())
                .rotate(0)
                .setCurveType(Animator.CurveType.DECELERATE)
                .setDuration(300)
                .setStateChangedListener(new Animator.StateChangedListener() {
                    @Override
                    public void onStart(Animator animator) {
                        setTouchComponent(cacheComponent);
                        componentList.add(0, cacheComponent);

                        if (componentList.size() > mDisplayViewCount) {
                            removeComponentAt(0);
                        }
                        cacheComponent = null;
                    }

                    @Override
                    public void onStop(Animator animator) {
                    }

                    @Override
                    public void onCancel(Animator animator) {
                    }

                    @Override
                    public void onEnd(Animator animator) {
                        setViewScale();
                    }

                    @Override
                    public void onPause(Animator animator) {
                    }

                    @Override
                    public void onResume(Animator animator) {
                    }
                }).start();
    }

    /**
     * 设置显示卡片数量
     *
     * @param count 卡片数量
     * @return SwipeDirectionalView
     */
    public SwipeDirectionalView setDisplayViewCount(int count) {
        this.mDisplayViewCount = count;
        return this;
    }

    /**
     * 设置滑动类型
     *
     * @param type 滑动类型
     * @return SwipeDirectionalView
     */
    public SwipeDirectionalView setSwipeType(int type) {
        this.mSwipeType = type;
        cardTouchEventListener.setSwipeType(type);
        return this;
    }

    /**
     * 设置卡片属性
     *
     * @param swipeDecor SwipeDecor
     * @return SwipeDirectionalView
     */
    public SwipeDirectionalView setSwipeDecor(SwipeDecor swipeDecor) {
        this.mSwipeDecor = swipeDecor;
        return this;
    }

    /**
     * 可触碰
     *
     * @return SwipeDirectionalView
     */
    public SwipeDirectionalView enableTouchSwipe() {
        this.isTouchAble = true;
        mTouchComponent.setTouchEventListener(cardTouchEventListener);
        return this;
    }

    /**
     * 设置不可触碰
     *
     * @return SwipeDirectionalView
     */
    public SwipeDirectionalView disableTouchSwipe() {
        this.isTouchAble = false;
        return this;
    }
}
